package sysRole

import (
	"context"
	"errors"
	"fmt"
	v1 "gf-admin/api/system/v1"
	"gf-admin/internal/consts"
	"gf-admin/internal/dao"
	"gf-admin/internal/logic/casbin"
	"gf-admin/internal/model"
	"gf-admin/internal/model/do"
	"gf-admin/internal/service"
	lib "gf-admin/utility/lib"
	"github.com/gogf/gf/v2/database/gdb"
	"github.com/gogf/gf/v2/frame/g"
	"github.com/gogf/gf/v2/util/gconv"
)

type sSysRole struct {
	casBinUserPrefix string //CasBin 用户id前缀
}

func New() *sSysRole {
	return &sSysRole{
		casBinUserPrefix: "u_",
	}
}
func init() {
	service.RegisterSysRole(New())
}

func (s *sSysRole) GetRoleListSearch(ctx context.Context, req *v1.RoleListReq) (res *v1.RoleListRes, err error) {
	res = &v1.RoleListRes{Content: &v1.RoleList{}}
	g.Try(ctx, func(ctx context.Context) {
		model := dao.SysRole.Ctx(ctx)
		if req.RoleName != "" {
			model = model.Where("name like ?", "%"+req.RoleName+"%")
		}
		if req.Status != "" {
			model = model.Where("status", gconv.Int(req.Status))
		}
		res.Content.Total, err = model.Count()
		lib.ErrIsNil(ctx, err, "获取角色数据失败")
		if req.PageNum == 0 {
			req.PageNum = 1
		}
		res.Content.CurrentPage = req.PageNum
		if req.PageSize == 0 {
			req.PageSize = consts.PageSize
		}
		err = model.Page(res.Content.CurrentPage, req.PageSize).Order("id asc").Scan(&res.Content.List)
		lib.ErrIsNil(ctx, err, "获取数据失败")
	})
	return
}

/*
获取角色列表(这是给用户管理那里要调用的)
*/
func (s *sSysRole) GetRoleList(ctx context.Context) (list []*model.SysRole, errs error) {
	var v = make([]*model.SysRole, 0)
	err := dao.SysRole.Ctx(ctx).Order(dao.SysRole.Columns().ListOrder + " asc," + dao.SysRole.Columns().Id + " asc").Scan(&v)
	if err != nil {
		return nil, err
	}
	if len(v) == 0 {
		return nil, errors.New("用户")
	}
	return v, nil
}

// 给用户管理那边使用的
func (s *sSysRole) AddUserRole(ctx context.Context, roleIds []int64, userId int64) (err error) {
	err = g.Try(ctx, func(ctx context.Context) {
		enforcer, e := casbin.CasbinEnforcer(ctx)
		lib.ErrIsNil(ctx, e)
		for _, v := range roleIds {
			_, e = enforcer.AddGroupingPolicy(fmt.Sprintf("%s%d", s.casBinUserPrefix, userId), gconv.String(v))
			lib.ErrIsNil(ctx, e)
		}
	})
	return
}

// AddRoleRule 添加角色权限
func (s *sSysRole) AddRoleRule(ctx context.Context, ruleIds []uint, roleId int64) (err error) {
	err = g.Try(ctx, func(ctx context.Context) {
		enforcer, e := casbin.CasbinEnforcer(ctx)
		lib.ErrIsNil(ctx, e)
		ruleIdsStr := gconv.Strings(ruleIds)
		for _, v := range ruleIdsStr {
			_, err = enforcer.AddPolicy(gconv.String(roleId), v, "All")
			lib.ErrIsNil(ctx, err)
		}
	})
	return
}

// BindRoleRule 绑定角色权限
func (s *sSysRole) BindRoleRule(ctx context.Context, ruleId interface{}, roleIds []uint) (err error) {
	err = g.Try(ctx, func(ctx context.Context) {
		enforcer, e := casbin.CasbinEnforcer(ctx)
		lib.ErrIsNil(ctx, e)
		for _, roleId := range roleIds {
			_, err = enforcer.AddPolicy(fmt.Sprintf("%d", roleId), fmt.Sprintf("%d", ruleId), "All")
			lib.ErrIsNil(ctx, err)
		}
	})
	return
}

// DeleteByIds 删除角色
func (s *sSysRole) DeleteByIds(ctx context.Context, ids []int64) (err error) {
	err = g.DB().Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {
		err = g.Try(ctx, func(ctx context.Context) {
			_, err = dao.SysRole.Ctx(ctx).TX(tx).Where(dao.SysRole.Columns().Id+" in(?)", ids).Delete()
			lib.ErrIsNil(ctx, err, "删除角色失败")
			//删除角色权限
			for _, v := range ids {
				err = s.DelRoleRule(ctx, v)
				lib.ErrIsNil(ctx, err)
			}

		})
		return err
	})
	return
}

// DelRoleRule 删除角色权限
func (s *sSysRole) DelRoleRule(ctx context.Context, roleId int64) (err error) {
	err = g.Try(ctx, func(ctx context.Context) {
		enforcer, e := casbin.CasbinEnforcer(ctx)
		lib.ErrIsNil(ctx, e)
		_, err = enforcer.RemoveFilteredPolicy(0, gconv.String(roleId))
		lib.ErrIsNil(ctx, e)
	})
	return
}

func (s *sSysRole) Get(ctx context.Context, id uint) (res *model.SysRole, err error) {
	err = g.Try(ctx, func(ctx context.Context) {
		err = dao.SysRole.Ctx(ctx).WherePri(id).Scan(&res)
		lib.ErrIsNil(ctx, err, "获取角色信息失败")
	})
	return
}

func (s *sSysRole) GetMenuRoles(ctx context.Context, id uint) (roleIds []uint, err error) {
	err = g.Try(ctx, func(ctx context.Context) {
		enforcer, e := casbin.CasbinEnforcer(ctx)
		lib.ErrIsNil(ctx, e)
		policies := enforcer.GetFilteredNamedPolicy("p", 1, gconv.String(id))
		for _, policy := range policies {
			roleIds = append(roleIds, gconv.Uint(policy[0]))
		}
	})
	return
}

// GetFilteredNamedPolicy 获取角色关联的菜单规则
func (s *sSysRole) GetFilteredNamedPolicy(ctx context.Context, id uint) (gpSlice []int, err error) {
	err = g.Try(ctx, func(ctx context.Context) {
		enforcer, e := casbin.CasbinEnforcer(ctx)
		lib.ErrIsNil(ctx, e)
		gp := enforcer.GetFilteredNamedPolicy("p", 0, gconv.String(id))
		gpSlice = make([]int, len(gp))
		for k, v := range gp {
			gpSlice[k] = gconv.Int(v[1])
		}
	})
	return
}

// EditRole 修改角色
func (s *sSysRole) EditRole(ctx context.Context, req *v1.RoleEditReq) (err error) {
	err = g.DB().Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {
		err = g.Try(ctx, func(ctx context.Context) {
			_, e := dao.SysRole.Ctx(ctx).TX(tx).WherePri(req.Id).Data(&do.SysRole{
				Status:    req.Status,
				ListOrder: req.ListOrder,
				Name:      req.Name,
				Remark:    req.Remark,
			}).Update()
			lib.ErrIsNil(ctx, e, "修改角色失败")
			//删除角色权限
			e = s.DelRoleRule(ctx, req.Id)
			lib.ErrIsNil(ctx, e)
			//添加角色权限
			e = s.AddRoleRule(ctx, req.MenuIds, req.Id)
			lib.ErrIsNil(ctx, e)

		})
		return err
	})
	return
}

// 添加角色,给角色管理使用的
func (s *sSysRole) AddRole(ctx context.Context, req *v1.RoleAddReq) (err error) {
	err = g.DB().Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {
		err = g.Try(ctx, func(ctx context.Context) {
			roleId, e := dao.SysRole.Ctx(ctx).TX(tx).InsertAndGetId(req)
			lib.ErrIsNil(ctx, e, "添加角色失败")
			//添加角色权限
			e = s.AddRoleRule(ctx, req.MenuIds, roleId)
			lib.ErrIsNil(ctx, e)

		})
		return err
	})
	return
}
